package com.mxpio.erp.inventory.service.impl;

import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.inventory.entity.*;
import com.mxpio.erp.common.order.policy.OrderContext;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.order.service.OrderService;
import com.mxpio.erp.common.plan.entity.OrganizationDemand;
import com.mxpio.erp.common.purchase.entity.PurchaseOrder;
import com.mxpio.erp.common.quality.entity.InventoryInspectApply;
import com.mxpio.erp.common.quality.entity.ScrapOutApply;
import com.mxpio.erp.common.sales.entity.SalesOrder;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpio.erp.common.vo.OrderExcuteVo;
import com.mxpio.erp.common.workshop.entity.ManufactureOrder;
import com.mxpio.erp.common.workshop.entity.OutsourceOrder;
import com.mxpio.erp.inventory.policy.impl.*;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mxpio.erp.common.inventory.service.WarehouseOrderService;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class WarehouseOrderServiceImpl extends BaseServiceImpl<WarehouseOrder> implements WarehouseOrderService {
    @Autowired
    private OrderService bizOrderService;
    @Autowired
    private OrderLineService orderLineService;
    @Override
    @Transactional
    public void executeBatch(OrderExcuteVo orderExcuteVo) {
        List<OrderExcuteLineVo> lines = orderExcuteVo.getLines();
        if (CollectionUtils.isEmpty(lines)){
            throw new MBootException("提交数据为空");
        }
        Map<String, List<OrderExcuteLineVo>> groupByBizNoMap = lines.stream().collect(Collectors.groupingBy(OrderExcuteLineVo::getBizWoNo));
        for (String bizNo:groupByBizNoMap.keySet()){
            WarehouseOrder warehouseOrder = this.getById(WarehouseOrder.class, bizNo);
            List<OrderExcuteLineVo> excuteLineVos = groupByBizNoMap.get(bizNo);
            OrderContext context = null;
            if (StringUtils.equals(warehouseOrder.getWoType(), NoticeStatusEnums.NoticeType.SO_OUT.getCode())){//销售出库
                context = bizOrderService.execute(warehouseOrder, new SaleWoPolicy(excuteLineVos,orderLineService));
            }else if (StringUtils.equals(warehouseOrder.getWoType(), NoticeStatusEnums.NoticeType.PO_IN.getCode())){
                context = bizOrderService.execute(warehouseOrder, new PurchaseWoPolicy(excuteLineVos,orderLineService));
            }else if (StringUtils.equals(warehouseOrder.getWoType(),NoticeStatusEnums.NoticeType.DO_IN.getCode())){//组织需求接料
                context = bizOrderService.execute(warehouseOrder, new OrganizationDemandWoPolicy(excuteLineVos,orderLineService));
            }else if (StringUtils.equals(warehouseOrder.getWoType(),NoticeStatusEnums.NoticeType.SOA_OUT.getCode())){//报废出库
                context = bizOrderService.execute(warehouseOrder, new DefaultWoWithHoldLotPolicy(excuteLineVos,orderLineService));
            }else if (StringUtils.equals(warehouseOrder.getWoType(),NoticeStatusEnums.NoticeType.IIA_IN.getCode())){//库存质检申请-转移入
                context = bizOrderService.execute(warehouseOrder, new IIAInWoPolicy(excuteLineVos,orderLineService));
            }else if (StringUtils.equals(warehouseOrder.getWoType(),NoticeStatusEnums.NoticeType.FP_IN.getCode())){//送货计划入
                context = bizOrderService.execute(warehouseOrder, new FeedPlanWoInPolicy(excuteLineVos,orderLineService));
            }else if (StringUtils.equals(warehouseOrder.getWoType(),NoticeStatusEnums.NoticeType.QO_IN.getCode())){//质检让步接收入
                context = bizOrderService.execute(warehouseOrder, new QOWoInPolicy(orderExcuteVo.getLines(),orderLineService));
            }else{
                context = bizOrderService.execute(warehouseOrder, new DefaultWoPolicy(excuteLineVos));
            }
            if(CollectionUtils.isNotEmpty(context.getErrors())) {
                throw new MBootException("仓单"+bizNo+"执行异常信息=>>"+context.getErrors().get(0));//抛出异常，事务回滚
            }
        }
    }

    @Override
    @Transactional
    public Result<List<WarehouseOrder>> listByNos(String bizNos) {
        if (StringUtils.isBlank(bizNos)){
            return Result.error("查询参数为空");
        }
        List<WarehouseOrder> returnList = JpaUtil.linq(WarehouseOrder.class).
                collect("bizNo", WarehouseOrderLine.class, "bizNo").
                in("bizNo", Stream.of(bizNos.split(",")).collect(Collectors.toList())).list();
        if (returnList.size()>0){//关联明细对应流水
            for (WarehouseOrder order:returnList){
                List<WarehouseOrderLine> warehouseOrderLines = order.getWarehouseOrderLines();
                if (warehouseOrderLines!=null&&warehouseOrderLines.size()>0){
                    for (WarehouseOrderLine line:warehouseOrderLines){
                        List<VInvFlow> invFlowBusiDetailList = JpaUtil.linq(VInvFlow.class).equal("woBizNo", line.getBizNo()).equal("woBizLineNo", line.getLineNo()).list();
                        line.setFlowList(invFlowBusiDetailList);
                    }
                }
            }
        }
        return Result.OK(returnList);
    }

    @Override
    @Transactional
    public Result<List<WarehouseOrder>> listByNosWithOrder(String bizNos) {
        if (StringUtils.isBlank(bizNos)){
            return Result.error("查询参数为空");
        }
        List<WarehouseOrder> returnList = JpaUtil.linq(WarehouseOrder.class).
                collect("bizNo", WarehouseOrderLine.class, "bizNo").
                in("bizNo", Stream.of(bizNos.split(",")).collect(Collectors.toList())).list();
        if (returnList.size()>0){//关联明细对应流水
            for (WarehouseOrder order:returnList){
                List<WarehouseOrderLine> warehouseOrderLines = order.getWarehouseOrderLines();
                if (warehouseOrderLines!=null&&warehouseOrderLines.size()>0){
                    for (WarehouseOrderLine line:warehouseOrderLines){
                        List<VInvFlow> invFlowBusiDetailList = JpaUtil.linq(VInvFlow.class).equal("woBizNo", line.getBizNo()).equal("woBizLineNo", line.getLineNo()).list();
                        line.setFlowList(invFlowBusiDetailList);
                    }
                }
                String originBizNo = order.getOriginBizNo();//关联上游业务单
                if (StringUtils.isNotBlank(originBizNo)){
                    ManufactureOrder manufactureOrder = JpaUtil.getOne(ManufactureOrder.class, originBizNo);
                    if (manufactureOrder!=null){
                        order.setOrder(manufactureOrder);
                        continue;//找到就跳过
                    }
                    PurchaseOrder purchaseOrder = JpaUtil.getOne(PurchaseOrder.class, originBizNo);//采购订单
                    if (purchaseOrder!=null){
                        order.setOrder(purchaseOrder);
                        continue;//找到就跳过
                    }
                    SalesOrder salesOrder = JpaUtil.getOne(SalesOrder.class, originBizNo);//销售订单
                    if (salesOrder!=null){
                        order.setOrder(salesOrder);
                        continue;//找到就跳过
                    }
                    OutsourceOrder outsourceOrder = JpaUtil.getOne(OutsourceOrder.class, originBizNo);
                    if (outsourceOrder!=null){
                        order.setOrder(outsourceOrder);
                        continue;//找到就跳过
                    }
                    OrganizationDemand organizationDemand = JpaUtil.getOne(OrganizationDemand.class, originBizNo);//组织需求
                    if (organizationDemand!=null){
                        order.setOrder(organizationDemand);
                        continue;//找到就跳过
                    }
                    ScrapOutApply scrapOutApply = JpaUtil.getOne(ScrapOutApply.class, originBizNo);//报废申请
                    if (scrapOutApply!=null){
                        order.setOrder(scrapOutApply);
                        continue;//找到就跳过
                    }
                    InventoryInspectApply inventoryInspectApply = JpaUtil.getOne(InventoryInspectApply.class, originBizNo);//库存检验申请
                    if (inventoryInspectApply!=null){
                        order.setOrder(inventoryInspectApply);
                        continue;//找到就跳过
                    }
                    FeedPlanNotice feedPlanNotice = JpaUtil.getOne(FeedPlanNotice.class, originBizNo);//送货计划
                    if (feedPlanNotice!=null){
                        order.setNotice(feedPlanNotice);
                    }
                    InitStockNotice initStockNotice = JpaUtil.getOne(InitStockNotice.class, originBizNo);//初始化通知单
                    if (initStockNotice!=null){
                        order.setInitStockNotice(initStockNotice);
                    }
                }
            }
        }
        return Result.OK(returnList);
    }

    @Override
    @Transactional
    public Result<Boolean> judgeJitOutWo(String bizNos) {//根据仓单的源通知单单号反查是否存在送货计划来判断当前仓单是否是jit物料对应的出库仓单
        Set<String> bizNosSet = Stream.of(bizNos.split(",")).collect(Collectors.toSet());
        List<WarehouseOrder> woList = JpaUtil.linq(WarehouseOrder.class).in("bizNo",bizNosSet ).list();
        if (woList==null){
            return Result.error("仓单单号未能匹配到对应仓单数据");
        }
        Set<String> originNoticeNoSet = woList.stream().map(WarehouseOrder::getOriginNoticeNo).collect(Collectors.toSet());
        List<FeedPlanNotice> feedPlanNoticeList = JpaUtil.linq(FeedPlanNotice.class).in("sourcePickingNoticeNo", originNoticeNoSet).list();
        if (feedPlanNoticeList.isEmpty()){
            return Result.OK(Boolean.FALSE);
        }else{
            return Result.OK(Boolean.TRUE);
        }
    }
}
